package cn.itcast.tanhua.mytanhuasso.service.impl;

import cn.hutool.core.util.StrUtil;
import cn.itcast.tanhua.constant.MessageConstant;
import cn.itcast.tanhua.constant.RedisKeyConstant;
import cn.itcast.tanhua.mytanhuadubbointerface.api.HuanXinApi;
import cn.itcast.tanhua.mytanhuasso.mapper.UserMapper;
import cn.itcast.tanhua.mytanhuasso.service.UserService;
import cn.itcast.tanhua.vo.ErrorResult;

import cn.itcast.tanhua.pojo.User;
import com.alibaba.dubbo.config.annotation.Reference;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.itheima.aliyunsmsspringbootstart.service.AliyunSmsService;
import io.jsonwebtoken.ExpiredJwtException;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import lombok.extern.slf4j.Slf4j;

import org.apache.commons.lang3.StringUtils;
import org.apache.rocketmq.spring.core.RocketMQTemplate;
import org.joda.time.DateTime;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.messaging.MessagingException;
import org.springframework.stereotype.Service;

import java.time.Duration;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
 * @author 郭文亮
 * @since 2021/11/22 19:59
 */
@Service
@Slf4j
public class UserServiceImpl implements UserService {

    @Autowired
    private AliyunSmsService aliyunSmsService;

    @Autowired
    private RedisTemplate<String, String> redisTemplate;

    @Autowired
    private UserMapper userMapper;

    @Value("${jwt.secret}")
    private String secret;

    @Autowired
    private RocketMQTemplate rocketMQTemplate;

    @Reference
    private HuanXinApi huanXinApi;

    @Override
    public ErrorResult sendCheckCode(String mobile) {
        String redisKey = RedisKeyConstant.CHECK_CODE_MOBILE + mobile;
        if (this.redisTemplate.hasKey(redisKey)) {
            // 如果存在对应的key，则返回消息发送重复
            return ErrorResult.builder()
                    .errCode(MessageConstant.CHECK_CODE_SEND_REPEAT_CODE)
                    .errMessage(MessageConstant.CHECK_CODE_SEND_REPEAT)
                    .build();
        }
        // 发送短信验证码，并获取验证码
        // String code = aliyunSmsService.sendSms(mobile);
        String code = "123456";
        if (StringUtils.isEmpty(code)) {
            // 如果code为null，返回发送失败
            return ErrorResult.builder()
                    .errCode(MessageConstant.CHECK_CODE_SEND_ERROR_CODE)
                    .errMessage(MessageConstant.CHECK_CODE_SEND_ERROR)
                    .build();
        }
        // 将code存入redis，设置有效期为5分钟
        this.redisTemplate.opsForValue().set(redisKey, code, Duration.ofMinutes(5));
        return null;
    }

    @Override
    public Map<String, Object> login(String mobile, String verificationCode) {
        if (verificationCode == null || "".equals(verificationCode)){
            return null;
        }
        String redisKey = RedisKeyConstant.CHECK_CODE_MOBILE + mobile;
        if (this.redisTemplate.hasKey(redisKey)) {
            boolean isNew = false;
            Map<String, Object> result = new HashMap<>();
            String redisCode = this.redisTemplate.opsForValue().get(redisKey);
            if (verificationCode.equals(redisCode)) {
                // 输入的验证码和redis中的验证码一致
                // 废弃redis中的验证码
                this.redisTemplate.delete(redisKey);
                // 1.校验是否为新用户 2.生成token
                LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper();
                queryWrapper.eq(User::getMobile, mobile);
                User user = this.userMapper.selectOne(queryWrapper);
                if (null == user) {
                    // 是新用户
                    user = new User();
                    user.setMobile(mobile);
                    // 往数据库中添加新用户
                    this.userMapper.insert(user);
                    isNew = true;

                    //注册环信用户
                    Boolean resultHX = this.huanXinApi.register(user.getId());
                    if (!resultHX) {
                        //注册环信失败，记录日志
                        log.error("注册环信用户失败~ userId = " + user.getId());
                    }
                }

                //判断标识status是否为1
                Map<String,Object> smap = new HashMap<>();
                Long userId = user.getId();
                String status = user.getStatus();
                if (status == null){
                    user.setStatus("0");
                    userMapper.updateById(user);
                }
                if (StrUtil.equals("1",status)){
                    smap.put("msg","用户被禁用");
                    return smap;
                }


                // 生成token
                Map<String, Object> claims = new HashMap<String, Object>();
                claims.put("id", user.getId());
                String token = Jwts.builder()
                        //payload，存放数据的位置，不能放置敏感数据，如：密码等
                        .setClaims(claims)
                        //设置加密方法和加密盐
                        .signWith(SignatureAlgorithm.HS256, secret)
                        //设置过期时间，12小时后过期
                        .setExpiration(new DateTime().plusHours(12).toDate())
                        .compact();
                // 将token存入result
                result.put("token", token);




                try {
                    //发送用户登录成功的消息
                    Map<String, Object> msg = new HashMap<>();
                    msg.put("id", user.getId());
                    msg.put("date", System.currentTimeMillis());

                    this.rocketMQTemplate.convertAndSend("tanhua-sso-login", msg);
                } catch (MessagingException e) {
                    log.error("发送消息失败！", e);
                }
                result.put("isNew", isNew);
                // 返回结果
                return result;
            }
        }
        return null;
    }

    @Override
    public User queryUserByToken(String token) {
        try {
            // 通过token解析数据
            Map<String, Object> body = Jwts.parser()
                    .setSigningKey(secret)
                    .parseClaimsJws(token)
                    .getBody();

            User user = new User();
            user.setId(Long.valueOf(body.get("id").toString()));

            //需要返回user对象中的mobile，需要查询数据库获取到mobile数据
            //如果每次都查询数据库，必然会导致性能问题，需要对用户的手机号进行缓存操作
            //数据缓存时，需要设置过期时间，过期时间要与token的时间一致
            //如果用户修改了手机号，需要同步修改redis中的数据
            String redisKey = RedisKeyConstant.TANHUA_USER_MOBILE_USERID + user.getId();
            String value = this.redisTemplate.opsForValue().get(redisKey);
//            if (redisTemplate.hasKey(redisKey)) {
                if (StrUtil.isNotEmpty(value)){
                // 如果redis中有对应的key，查询redis中的status存入user
                String status = redisTemplate.opsForValue().get(redisKey);
                user.setStatus(status);
            } else {
                // 1.从数据库中通过id查出对应的数据，获取状态。 2.将状态存入redis
                LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
                queryWrapper.eq(User::getId, user.getId());
                User userById = userMapper.selectOne(queryWrapper);
                //user.setMobile(userById.getMobile());
                user.setStatus(userById.getStatus());
                // 将信息存入redis,有效期和token的保持一致
                long timeout = Long.valueOf(body.get("exp").toString()) * 1000 - System.currentTimeMillis();
                redisTemplate.opsForValue().set(redisKey, userById.getStatus(), timeout, TimeUnit.MILLISECONDS);

            }
            return user;
        } catch (ExpiredJwtException e) {
            log.info("token已经过期！ token = " + token);
        } catch (Exception e) {
            log.error("token不合法！ token = " + token, e);
        }
        return null;
    }


    /**
     * 用户禁用
     * @author 林金洋
     * @param userId
     * @return
     */
    @Override
    public Map<String, Object> releaseDown(Long userId) {
        QueryWrapper<User> queryWrapper = new QueryWrapper();
        queryWrapper.eq("id",userId);
        User user = this.userMapper.selectOne(queryWrapper);
        user.setStatus("1");
        userMapper.updateById(user);

        Map<String,Object> rmap = new HashMap<>();
        rmap.put("msg","该用户已禁用");
        rmap.put("user",user);

        return rmap;
    }

    /**
     * 通过id查询用户数据
     *
     * @param userId
     * @return
     */
    @Override
    public User queryUserByUserId(Long userId) {
        return userMapper.selectById(userId);
    }

    /**
     * 用户解禁
     * @author 林金洋
     * @param userId
     * @return
     */
    @Override
    public Map<String,Object> releaseOn(Long userId) {
        QueryWrapper<User> queryWrapper = new QueryWrapper();
        queryWrapper.eq("id",userId);
        User user = this.userMapper.selectOne(queryWrapper);
        user.setStatus("0");
        userMapper.updateById(user);

        Map<String,Object> rmap = new HashMap<>();
        rmap.put("msg","该用户已解禁");
        rmap.put("user",user);

        return rmap;
    }
}
